package com.tl.spider.utils.dedicated_utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import com.tl.spider.config.Config;

/**
 * 下载html网页的工具类
 * 
 * @date 2021年7月18日
 * @author Antg
 */
public class WebPageUtil {
	/**
	 * 使用HttpURLConnection下载网页
	 * 
	 * @param url
	 * @param charset
	 * @return
	 * @throws IOException
	 * @date 2021年7月18日
	 * @author Antg
	 */
	public static String getWebPageCodeWithHttpURLConnection(String url,
			String charset) throws IOException {
		// 拿到Url的java对象
		URL urlObj = new URL(url);
		// 建立http连接(URLConnection不可关闭连接,所以就转成它的子类)
		HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
		// 通过这个连接就可以获取输入流,即可以获取到对应的html代码
		InputStream is = conn.getInputStream();
		InputStreamReader isr = new InputStreamReader(is, charset);
		BufferedReader br = new BufferedReader(isr);
		String bufLine = null;
		// 将网页内容追加到一个字符串中
		StringBuilder sBuilder = new StringBuilder();
		int counter = 0;
		while ((bufLine = br.readLine()) != null) {
			if (counter > 0) {
				sBuilder.append("\n");
			}
			sBuilder.append(bufLine);
			counter++;
		}
		// 关流,关网页连接
		br.close();
		conn.disconnect();
		return sBuilder.toString();
	}

	/**
	 * 使用HttpClient下载网页代码(这个是最常用的,它封装了HttpURLConnection)
	 * 
	 * @param url
	 * @param charset
	 * @return
	 * @date 2021年7月18日
	 * @author Antg
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String getWebPageCodeWithHttpClient(String url, String charset)
			throws ClientProtocolException, IOException {
		// 获取HttpClient采集引擎
		CloseableHttpClient httpClient = HttpClients.createDefault();
		// 建立get请求
		HttpGet httpGet = new HttpGet(url);
		// 可以在这里设置请求的头部,这里就不设置了,因为爬取的是一个简单的网站,没有反爬措施

		// 获取响应
		CloseableHttpResponse resp = httpClient.execute(httpGet);
		// 判断响应是否成功(响应成功才返回代码)
		if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			// 获取对象流的实体对象(HttpEntity)
			HttpEntity httpEntity = resp.getEntity();
			// 获取String形式的code
			return EntityUtils.toString(httpEntity, charset);
		} else {
			System.out.println("页面打开失败,请检查url是否可以打开--->" + url);
			return null;
		}
	}

	/**
	 * 使用HttpClient下载网页代码<br>
	 * 自动获取编码
	 * 
	 * @param url
	 * @param charset
	 * @return
	 * @date 2021年7月18日
	 * @author Antg
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String getWebPageCodeWithHttpClient(String url)
			throws ClientProtocolException, IOException {
		String charset = "";
		// 获取HttpClient采集引擎
		CloseableHttpClient httpClient = HttpClients.createDefault();
		// 建立get请求
		HttpGet httpGet = new HttpGet(url);
		// 可以在这里设置请求的头部,这里就不设置了,因为爬取的是一个简单的网站,没有反爬措施

		// 获取响应
		CloseableHttpResponse resp = httpClient.execute(httpGet);
		// 判断响应是否成功(响应成功才返回代码)
		if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

			// 获取对象流的实体对象(HttpEntity)
			HttpEntity httpEntity = resp.getEntity();
			// 首先从header中获取编码
			charset = EntityUtils.getContentCharSet(httpEntity);
			// 获取页面代码(无编码方式的)
			byte[] code = EntityUtils.toByteArray(httpEntity);
			if (charset == null) {
				// System.out.println("header中未获取charset");
				// 如果没有获取到就从页面代码中获取
				charset = getWebPageCharsetFromCode(code);
				if (charset == null) {
					// System.out.println("mate中未获取charset");
					// 如果还是没有找到就使用使用配置中的代码
					charset = Config.web_page_charset;
				}
			}
			// System.out.println("字符编码--->" + charset);
			httpClient.close();
			resp.close();
			return new String(code, charset);
		} else {
			System.out.println("页面打开失败,请检查url是否可以打开--->" + url);
			return null;
		}
	}

	/**
	 * 从页面代码中获取charset(这里不用管什么编码,因为还不知道编码)
	 * 
	 * @param code
	 * @return
	 * @date 2021年7月18日
	 * @author Antg
	 */
	public static String getWebPageCharsetFromCode(byte[] code) {
		// 这里使用了正则的非贪婪算法--->*?
		String regex = "(?i)<meta[\\s\\S]*?charset=[\"]?(.*)\"";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(new String(code));
		if (matcher.find()) {
			return matcher.group(1);
		} else {
			return null;
		}
	}
}
